/**
 * 创建 threejs 四大天王
 * 场景、相机、渲染器、控制器
 */

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export interface CameraPosition {
  x?: number
  y?: number
  z?: number
}
export interface CameraConfig {
  fov?: number
  aspect?: number
  near?: number
  far?: number
  position?: CameraPosition
}
export interface ThreeBasicProps {
  dom: HTMLElement
  innerWidth?: number
  innerHeight?: number
  cameraConfig?: CameraConfig
}

export class ThreeBasic {
  public scene!: THREE.Scene
  public camera!: THREE.PerspectiveCamera
  public renderer!: THREE.WebGLRenderer
  public controls!: OrbitControls
  public dom: HTMLElement
  public innerWidth: number | undefined
  public innerHeight: number | undefined
  public cameraConfig?: CameraConfig
  constructor({ dom, innerWidth, innerHeight, cameraConfig }: ThreeBasicProps) {
    this.dom = dom
    this.innerWidth = innerWidth
    this.innerHeight = innerHeight
    this.initScenes()
    this.setControls()
  }

  /**
   * 初始化场景
   */
  initScenes() {
    this.scene = new THREE.Scene()
    const innerWidth = this.innerWidth || window.innerWidth
    const innerHeight = this.innerHeight || window.innerHeight
    const { fov, aspect, near, far, position } = this.cameraConfig || {}
    this.camera = new THREE.PerspectiveCamera(fov, innerWidth / innerHeight, near, far)
    const cameraPos: CameraConfig['position'] = position || {}
    this.camera.position.set(cameraPos.x || 1.5, cameraPos.y || 4, cameraPos.z || 9)

    this.renderer = new THREE.WebGLRenderer({
      // canvas: this.dom,
      alpha: true, // 透明
      antialias: true, // 抗锯齿
      preserveDrawingBuffer: true // 保留绘图缓存
    })
    this.renderer.setPixelRatio(window.devicePixelRatio) // 设置屏幕像素比
    this.renderer.setSize(innerWidth, innerHeight) // 设置渲染器宽高
    this.dom.appendChild(this.renderer.domElement) // 添加到dom中
  }

  /**
   * 设置控制器
   */
  setControls() {
    // 鼠标控制      相机，渲染dom
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)

    this.controls.autoRotateSpeed = 3
    // 使动画循环使用时阻尼或自转 意思是否有惯性
    this.controls.enableDamping = true
    // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
    this.controls.dampingFactor = 0.05
    // 是否可以缩放
    this.controls.enableZoom = true
    // 是否开启右键拖拽
    this.controls.enablePan = false
  }

  public render() {
    requestAnimationFrame(this.render.bind(this))
    this.renderer.render(this.scene, this.camera)
    this.controls && this.controls.update()
  }
  public dispose() {
    this.renderer.dispose()
  }
  public resize(innerWidth?: number, innerHeight?: number) {
    const _innerWidth = innerWidth || this.innerWidth || window.innerWidth
    const _innerHeight = innerHeight || this.innerHeight || window.innerHeight
    this.camera!.aspect = _innerWidth / _innerHeight
    this.camera!.updateProjectionMatrix()
    this.renderer.setSize(_innerWidth, _innerHeight)
  }
}
